#include "gwbase/base/string_util.h"
#include <stdarg.h>
#include <stdio.h>
#include <algorithm>

namespace dicom {

void StringPrintfV(std::string* result, const char* fmt, va_list ap) {
  // try to write to stack buffer directly
  char buffer[500];
  va_list copy;

  va_copy(copy, ap);
  int n = vsnprintf(buffer, 500, fmt, copy);
  va_end(ap);

  // a return value of size or more means that the output was truncated
  if (n < 500) {
    result->assign(buffer);
    return;
  }

  va_copy(copy, ap);
  n = vsnprintf(NULL, 0, fmt, copy);
  va_end(ap);

  char* b = new char[n];
  va_copy(copy, ap);
  vsnprintf(b, n, fmt, copy);
  va_end(ap);
  result->assign(b);
  delete[] b;
}

void StringPrintf(std::string* result, const char* fmt, ...) {
  va_list ap;
  va_start(ap, fmt);
  StringPrintfV(result, fmt, ap);
  va_end(ap);
}

std::string StringPrintf(const char* fmt, ...) {
  std::string result;
  va_list ap;
  va_start(ap, fmt);
  StringPrintfV(&result, fmt, ap);
  va_end(ap);

  return result;
}

void SplitToLines(const std::string& src, std::vector<Slice>* out) {
  size_t start = 0;
  bool seen_r = false;
  if (src.empty()) return;

  for (size_t i = 0; i < src.size(); ++i) {
    if (src[i] == '\n') {
      out->push_back(Slice(&src[start], i - start - (seen_r ? 1 : 0)));
      seen_r = false;
      start = i + 1;
    } else if (src[i] == '\r') {
      seen_r = true;
    }
  }

  if (start != src.size() - 1) {
    out->push_back(Slice(&src[start], src.size() - start));
  }
}

std::string LowerString(const std::string& src) {
  std::string dest = src;
  std::transform(src.begin(), src.end(), dest.begin(), ::tolower);
  return dest;
}

void InplaceLowerString(std::string& str) {
  std::transform(str.begin(), str.end(), str.begin(), ::tolower);
}
}
